<template>
	<view
		ref="bodywk"
		@click="hanlder"
		:class="[customClass, 'overflow']"
		:style="[computedHeight ? { height: computedHeight } : '', computedWidth ? { width: computedWidth } : '', customCSSStyle]"
	>
		<!-- #ifdef APP-NVUE -->
		<view
			v-if="isLoadEl"
			ref="nvueElAni"
			:animation="animationData"
			:class="['flex-col flex ', animationName + reverseAniPrefxname, customClass]"
		>
			<slot name="default"></slot>
		</view>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<view
			v-if="isLoadEl"
			ref="nvueElAni"
			:style="{
				transitionDuration: `${durationtos}ms`,
				transitionTimingFunction: 'cubic-bezier(.04,.78,.42,1)'
			}"
			:class="['flex-col flex ', animationClassName, customClass]"
		>
			<slot name="default"></slot>
		</view>
		<!-- #endif -->
	</view>
</template>

<script lang="ts" setup>
/**
 * 动画
 * @description 提供了6组动画，并且每组件动画都支持反转播放，相当于12组动画了。可用于任何元素，进入场和出场的动画。
 */
import { getCurrentInstance, computed, ref, provide, inject, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { cssstyle, tmVuetify } from '../../tool/lib/interface'
import { custom_props, computedClass, computedStyle } from '../../tool/lib/minxs'
// #ifdef APP-PLUS-NVUE
const Binding = uni.requireNativePlugin('bindingx')
const dom = uni.requireNativePlugin('dom')
const animation = uni.requireNativePlugin('animation')
// #endif
// 混淆props共有参数
const props = defineProps({
	...custom_props,
	duration: {
		type: Number,
		default: 300
	},
	delay: {
		type: Number,
		default: 0
	},
	//动画名称
	name: {
		type: String,
		default: 'fade' //fade,left,right,up,down,zoom
	},
	autoPlay: {
		type: Boolean,
		default: true
	},
	disabled: {
		type: Boolean,
		default: false
	},
	height: {
		type: [Number, String],
		default: 0
	},
	width: {
		type: [Number, String],
		default: 0
	},
	//是否反向动画
	reverse: {
		type: [Boolean, String],
		default: false
	},
	//每变动一次，就重置动画一下，这个属性不对外，特殊情况使用。
	initByWechat: {
		type: Boolean,
		default: false
	}
})
const emits = defineEmits(['start', 'end', 'click'])

function hanlder(e: any) {
	emits('click', e)
}
const proxy = getCurrentInstance()?.proxy ?? null
//自定义样式：
const customCSSStyle = computed(() => computedStyle(props))
//自定类
const customClass = computed(() => computedClass(props))
//高度，
const computedHeight = computed(() => {
	if (!props.height || !Number(props.height)) {
		return 0
	}
	if (String(props.height).indexOf('px') > -1 || String(props.height).indexOf('rpx') > -1) {
		return String(props.height)
	}
	return String(props.height) + 'rpx'
})

// 宽度
const computedWidth = computed(() => {
	if (!props.width) {
		return 0
	}
	if (String(props.width).indexOf('px') > -1 || String(props.width).indexOf('rpx') > -1) {
		return props.width
	}
	return props.width + 'rpx'
})
//动画名称
const animationName = computed(() => props.name || 'fade')
//动画时长
const durationtos = ref(props.duration)
//是否反转。
const computedReverse = computed(() => props.reverse)
//反转动画前缀
const reverseAniPrefxname = computed(() => (computedReverse.value ? '-reverse' : ''))
//非nvue
const animationClassName = ref(animationName.value + reverseAniPrefxname.value)
//动画播放状态。0未开始,结束播放，1开始播放中,2结束。
const animationStatus = ref(0)
const tmid = ref<any>(Number(uni.$tm.u.getUid(3)))
//是否渲染完成。
const isLoadEl = ref(false)
//css3动画数据。
const animationData = ref(null)
watch([() => props.initByWechat, () => props.name], () => {
	reset()
})
watch([() => props.name], () => {
	animationClassName.value = animationName.value + reverseAniPrefxname.value
})
function init() {
	nextTick(() => {
		isLoadEl.value = true
		if (props.autoPlay == true && !props.disabled) {
			nextTick(() => play())
		}
	})
}

function play() {
	if (props.disabled == true) return
	animationStatus.value = 0
	// #ifdef APP-NVUE
	clearTimeout(tmid.value)
	nextTick(function () {
		tmid.value = setTimeout(function () {
			emits('start')
			nvueAmatons()
		}, 50)
	})
	// #endif
	// #ifndef APP-NVUE
	noNvueAmations()
	// #endif
}

function stop() {
	if (props.disabled == true) return
	clearTimeout(tmid.value)
	animationStatus.value = 0
}

function reset() {
	stop()
	animationStatus.value = 0
}
//对外暴露方法。
defineExpose({
	init: init,
	play: play,
	stop: stop,
	reset: reset
})
//获取当前播放状态。
function getPlayStatus() {
	return animationStatus.value
}

onMounted(() => init())
onUnmounted(() => {
	clearTimeout(tmid.value)
	animationStatus.value = 0
})
function nvueAmatonsReset() {
	var el = proxy?.$refs.nvueElAni
	let propsAni = {}
	let rs = !computedReverse.value
	return new Promise((su) => {
		if (animationName.value == 'fade') {
			propsAni = {
				opacity: rs ? 0 : 1,
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'up') {
			propsAni = {
				opacity: 1,
				transform: rs ? 'translateY(0%)' : 'translateY(-100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'down') {
			propsAni = {
				opacity: 1,
				transform: rs ? 'translateY(0%)' : 'translateY(100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'right') {
			propsAni = {
				opacity: 1,
				transform: rs ? 'translateX(0%)' : 'translateX(100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'left') {
			propsAni = {
				opacity: 1,
				transform: rs ? 'translateX(0%)' : 'translateX(-100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'zoom') {
			propsAni = {
				opacity: rs ? 0 : 1,
				transform: rs ? 'scale(0.7,0.7)' : 'scale(1,1)',
				transformOrigin: 'center center'
			}
		}
		animation.transition(
			el,
			{
				styles: propsAni,
				duration: 1, //ms
				timingFunction: 'ease',
				delay: 0 //ms
			},
			() => {
				su(true)
			}
		)
	})
}
function nvueAmatons() {
	var el = proxy?.$refs.nvueElAni
	let propsAni = {}
	nvueAmatonsReset().then(() => {
		if (animationName.value == 'fade') {
			propsAni = {
				opacity: computedReverse.value ? 0 : 1,
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'up') {
			propsAni = {
				opacity: 1,
				transform: computedReverse.value ? 'translateY(0%)' : 'translateY(-100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'down') {
			propsAni = {
				opacity: 1,
				transform: computedReverse.value ? 'translateY(0%)' : 'translateY(100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'right') {
			propsAni = {
				opacity: 1,
				transform: computedReverse.value ? 'translateX(0%)' : 'translateX(100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'left') {
			propsAni = {
				opacity: 1,
				transform: computedReverse.value ? 'translateX(0%)' : 'translateX(-100%)',
				transformOrigin: 'center center'
			}
		} else if (animationName.value == 'zoom') {
			propsAni = {
				opacity: computedReverse.value ? 0 : 1,
				transform: computedReverse.value ? 'scale(0.7,0.7)' : 'scale(1,1)',
				transformOrigin: 'center center'
			}
		}
		emits('start')
		animationStatus.value = 1
		clearTimeout(tmid.value)
		tmid.value = setTimeout(function () {
			animation.transition(
				el,
				{
					styles: propsAni,
					duration: props.duration, //ms
					timingFunction: 'cubic-bezier(.04,.78,.42,1)',
					delay: 0 //ms
				},
				() => {
					emits('end')
					animationStatus.value = 2
				}
			)
		}, 20)
	})
}

function noNvueAmations() {
	clearTimeout(tmid.value)
	tmid.value = setTimeout(() => {
		if (computedReverse.value) {
			animationClassName.value = animationName.value
		} else {
			animationClassName.value = animationName.value + '-reverse'
		}
		tmid.value = setTimeout(() => {
			emits('end')
		}, props.duration)
	}, 20)
}
</script>

<style scoped>
.fade {
	opacity: 0;
}

.fade-reverse {
	opacity: 1;
}

.up {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateY(0%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	position: absolute;
	top: 0%;
	/* #endif */
}

.up-reverse {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateY(-101%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	position: absolute;
	top: -100%;
	/* #endif */
}

.down {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateY(0%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	position: absolute;
	bottom: 0%;
	/* #endif */
}

.down-reverse {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateY(101%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	position: absolute;
	bottom: -100%;
	/* #endif */
}

.left {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateX(0%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	left: 0%;
	position: absolute;
	/* #endif */
}

.left-reverse {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateX(-101%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	left: -101%;
	position: absolute;
	/* #endif */
}

.right {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateX(0%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	right: 0%;
	position: absolute;
	/* #endif */
}

.right-reverse {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: translateX(101%);
	/* #endif */
	/* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	right: -101%;
	position: absolute;
	/* #endif */
}

.zoom {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: scale(0.7, 0.7);
	/* #endif */
	opacity: 0;
}

.zoom-reverse {
	/* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
	transform: scale(1, 1);
	/* #endif */
	opacity: 1;
}
</style>
